package com.springcloud.hystrixdemo.service

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult
import com.netflix.hystrix.exception.HystrixBadRequestException
import org.springframework.stereotype.Service

import java.util.concurrent.Future

@Service
class UserService {
//仅在本次请求中有效
    //缓存结果
    @CacheResult
    @HystrixCommand(fallbackMethod = 'error',commandKey = 'getUser')
    String getUser(@CacheKey String name)
    {

        println('调用一次get方法')

        if (name.length()>5)
            throw new HystrixBadRequestException('请求参数过长')
        if (name!='ding')
            throw new RuntimeException("查无此人")

        '用户:'+name
    }

    /*
       fallbackMethod只能捕获系统异常(获取不到服务器的响应),如连接拒绝/超时等
       对于请求本身存在的问题(能够获取到服务器的响应,并且响应码大于等于300,错误被封装为HystrixBadRequestException),fallback方法则不会处理
    */
    String error(String name,Throwable e)
    {
        "${e.message}:${name}"
    }

    //移除缓存
    @CacheRemove(commandKey  = 'getUser')
    @HystrixCommand
    void  clear(@CacheKey String name)
    {
        println('清理缓存')
    }


//scope如何为GLOBAL则对所有请求聚合,如果为REQUEST则仅对本次请求有效
    //聚合请求,batchMethod指定聚合方法,使用timerDelayInMilliseconds参数指定聚合多长时间内的请求.方法返回值必须是Future<>类型
    @HystrixCollapser(batchMethod = 'collapseList',collapserProperties = @HystrixProperty(name = 'timerDelayInMilliseconds',value = '1000'),scope =com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL)
    Future<String> collapse(String key)
    {
    }

    @HystrixCommand
    List<String> collapseList(List<String> keys)
    {
        println("当前线程:${Thread.currentThread().name}")

        def r=[]
        keys.each {
            println("处理${it}")
            r<<"值${it}"
        }
        r
    }


    /*
        使用@HystrixCommand注解的方法会被Hystrix接管
            Hystrix有两种资源隔离策略:
                1.线程隔离(默认):请求将被转移至Hystrix线程池中的线程处理,原线程可以执行其他操作或阻塞.这种策略会导致依赖ThreadLocal存放数据的媒介失效
                2.信号量:依然使用原线程
     */
    @HystrixCommand(fallbackMethod = 'tFallback')
    def t(Thread thread)
    {

        //休眠时间存在50毫秒的上下浮动,模拟任务超时
        sleep(520+new Random().nextInt(50))

        println("执行t方法的线程:${Thread.currentThread().name}")
        //原线程将会wait
        println("原线程状态:${thread.name}-${thread.state}")
    }

    def tFallback(Thread thread,Throwable e)
    {
        println("${thread.name}:执行回退${e}")
    }

}
